const { src, dest, parallel, series, watch } = require('gulp')

const loadPlugins = require('gulp-load-plugins')
const del = require('del')
const browserSync = require('browser-sync')

//通过gulp-load-plugins自动加载插件，无需再次引用
const plugins = loadPlugins()
const bs = browserSync.create()  //创建开发服务器

//swig data
const data = {
    menus: [
      {
        name: 'Home',
        icon: 'aperture',
        link: 'index.html'
      },
      {
        name: 'Features',
        link: 'features.html'
      },
      {
        name: 'About',
        link: 'about.html'
      },
      {
        name: 'Contact',
        link: '#',
        children: [
          {
            name: 'Twitter',
            link: 'https://twitter.com/w_zce'
          },
          {
            name: 'About',
            link: 'https://weibo.com/zceme'
          },
          {
            name: 'divider'
          },
          {
            name: 'About',
            link: 'https://github.com/zce'
          }
        ]
      }
    ],
    pkg: require('./package.json'),
    date: new Date()
}

const clean = () => {
    return del(['dist', 'tmp'])
}

//样式编译,创建一个style的任务
const style = () => {
    //设置{base: 'src'} 保留src下目录结构
    return src('src/assets/styles/*.scss', {base: 'src'}) //src 读取文件流
        .pipe(plugins.sass({ outputStyle: 'expanded' })) //文件转换流,安装gulp-sass,默认转换不带下划线开头的css文件
        .pipe(dest('tmp')) //dest制定文件输出tmp目录
        .pipe(bs.reload({ stream: true }))  //刷新将流写入html
}

//js脚本编译
//安装一个脚本编译插件gulp-babel, 还需要安装babel核心模块 @babel/core @babel/preset-env
//babel只是提供转换平台，babel里面的插件实现转换操作，preset-env最新的特性转换打包
const script = () => {
    return src('src/assets/scripts/*.js', { base: 'src' })
        .pipe(plugins.babel( { presets: ['@babel/preset-env'] } ))
        .pipe(dest('tmp'))
        .pipe(bs.reload({ stream: true }))
}

//页面模板编译,安装模板引擎插件gulp-swig
const html = () => {
    return src('src/*.html', { base: 'src' })
        .pipe(plugins.swig( { data, defaults: { cache: false } } )) //defaults: { cache: false } 防止模板缓存导致页面不能及时刷新
        .pipe(dest('tmp'))
        .pipe(bs.reload({ stream: true }))
}

//图片和字体文件转换,安装插件gulp-imagemin
const img = () => {
    return src('src/assets/images/**',  { base: 'src' })
        .pipe(plugins.imagemin())
        .pipe(dest('dist'))
}

const font = () => {
    return src('src/assets/fonts/**',  { base: 'src' })
        .pipe(plugins.imagemin())
        .pipe(dest('dist'))
}

const extra = () => {
    return src('public/**',  { base: 'public' })
        .pipe(dest('dist'))
}

//创建服务器任务
const serve = () => {
    watch('src/assets/style/*scss', style)
    watch('src/assets/scripts/*.js', script)
    watch('src/*.html', html)
    //以下监视在开发阶段可以不执行，但是要在baseDir配置相应的路径，不然服务启动的时候找不到对应的资源
    // watch('src/assets/images/**', img)
    // watch('src/assets/fonts/**', font)
    // watch('public/**', extra)
    // 如果要监视图片或者文字的修改，使用bs。reload函数
    watch([
        'src/assets/images/**',
        'src/assets/fonts/**',
        'public/**'
    ], bs.reload)
    bs.init({  //初始化服务器相关配置
        notify: false,  //解决浏览器右上角connect 提示
        port: 3333,  //指定特定访问端口
        //files: 'tmp/**',  //Browsersync可以在工作中监听文件,修改指定目录下的文件自动刷新浏览器
        // open: false,  //是否自动启动浏览器
        server: {  
            baseDir: ['tmp', 'src', 'public'],  //指定服务启动时找到对应的资源目录
            routes: {   //优先baseDir,如果有就先执行routers
                '/node_modules': 'node_modules'
            }
        }
    })
}

//将css 文件合并成一个文件，
//<!-- build:css assets/styles/vendor.css --><!-- endbuild -->
//在build和endbuild之间的文件路径在build时都会打包成指定的文件名
const useref= () => {
  return src('tmp/*html',{base: 'tmp'})
    //searchPath找到build指定的目录，进行转换
    .pipe(plugins.useref( { searchPath: ['tmp', '.']}))
    //安装gulp-if判断读取的是什么文件
    .pipe(plugins.if(/\.js$/, plugins.uglify()))  //gulp-uglify 压缩js文件
    .pipe(plugins.if(/\.css$/, plugins.cleanCss())) //gulp-clean-css 压缩css文件
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({   //gulp-htmlmin 压缩html文件
          collapseWhitespace: true,  //对html清除空白字符
          minifyCSS: true,            //对html行内样式清除空白字符
          minifyJS: true             //对html中的JS清除空白字符
    })))
    .pipe(dest('dist'))
}

//创建组合任务,执行并行任务
const compile = parallel( style, script, html)

//把src同级的任务放在build任务中, series串行执行任务，先执行完clean，在执行生成文件，避免文件生成后又被删除的情况
const build = series(clean, parallel(series(compile, useref), img, font, extra)) //这里把img和font放在build任务是因为在上线时需要压缩这些文件，如果放在开发阶段会影响开发效率

//开发阶段执行的任务
const develop = series(compile, serve)

module.exports = {
    compile,
    clean,
    build,
    serve,
    develop,
    useref
}